<?php

namespace app\admins\controller;

use app\BaseController;
use think\facade\Filesystem;
use think\facade\Request;
use think\facade\Db;

class Files extends BaseController
{
    // 文件列表
    public function index()
    {
        if ($this->request->isAjax()) {
            $param = $this->request->param();
            // 搜索
            $map = [];
            if (!empty($param['search'])) {
                foreach ((array)$param['search'] as $k => $v) {
                    if (strlen($v)) $map[] = [$k, 'like', "%{$v}%"];
                }
            }
            // 查询
            $list = Db::table('files')->order('id', 'desc')->where($map);
            $data['count'] = $list->count();
            if ($data['count']) {
                $data['code'] = 0;
            } else {
                $data['code'] = 1;
                $data['msg'] = '暂无记录';
            }
            // 分页
            $list = $list->page($param['page'], $param['limit']);
            $data['data'] = $list->select()->map(function ($item) {
                $file = $this->app->getRootPath() . '/public/' . $item['path'];
                $item['preview'] = preg_match('/\/storage\/.+?\.(gif|jpg|jpeg|png|bmp|webp|psd|svg|tiff)$/i', $item['path']) ? (is_file(str_replace('\\', DIRECTORY_SEPARATOR, $file)) ? '<img src="' . $item['path'] . '" style="width:50%;height:100%" alt="preview" />' : '404 Err!') : '';
                $item['size'] = is_file(str_replace('\\', DIRECTORY_SEPARATOR, $file)) ? round(filesize(str_replace('\\', DIRECTORY_SEPARATOR, $file)) / 1024 * 100) / 100 . ' KB' : '';
                $item['time'] = date('Y-m-d H:i:s', $item['time']);
                $status_info = [0 => '<span style="color:green">正常</span>', 1 => '<span style="color:red">未使用</span>', 2 => '<span style="color:grey;text-decoration:line-through;">失效</span>'];
                $item['status_info'] = $status_info[$item['status']];
                return $item;
            });
            exit(json_encode($data));
        }
        // 限制上传类型
        $setting = DB::table('setting')->where('names', 'base_setting')->find();
        $exts = 'gif|jpg|jpeg|png';
        $size = 2048;
        if ($setting && isset($setting['values'])) {
            $values = json_decode($setting['values'], true);
            $exts = $values['exts'] ?? 'gif|jpg|jpeg|png';
            $size = $values['size'] ?? 2048;
        }
        return view('/files/index', ['exts' => $exts, 'size' => $size]);
    }

    // 商品图片上传
    public function upload_img()
    {
        $file = $this->request->file('file');
        $savename = Filesystem::disk('public')->putFile('product_imgs', $file);
        // 检查上传类型
        $setting = DB::table('setting')->where('names', 'base_setting')->find();
        $exts = 'gif|jpg|jpeg|png';
        $size = 2048;
        if ($setting && isset($setting['values'])) {
            $values = json_decode($setting['values'], true);
            $exts = $values['exts'] ?? 'gif|jpg|jpeg|png';
            $size = $values['size'] ?? 2048;
        }
        // 上传验证
        $rule = [
            'file' => [
                // 限制文件大小(单位b)，这里限制为4M
                'fileSize' => $size * 1024,
                // 限制文件后缀，多个后缀以英文逗号分割
                'fileExt'  => str_replace('|', ',', $exts),
            ],
            'message' => [
                'file.fileSize' => '文件太大',
                'file.fileExt' => '不支持的文件后缀',
            ]
        ];
        $validate = $this->app->validate->rule($rule);
        if (!$validate->check(['file' => $file])) {
            // 静默删除临时文件
            @unlink($file->getRealPath());
            exit(json_encode(['code' => 1, 'msg' => $validate->getError()]));
        }
        // $ext = $file->extension();
        // if (!in_array($ext, explode(',',$exts))) {
        //     // 静默删除临时文件
        //     @unlink($file->getRealPath());
        //     die(json_encode(['code' => 1, 'msg' => '不允许的上传类型' . $ext]));
        // }
        // // 检查文件大小
        // $file_size = round(filesize($file->getRealPath()) / 1024 * 100) / 100;
        // if ($file_size > (int)$size) {
        //     @unlink($file->getRealPath());
        //     die(json_encode(['code' => 1, 'msg' => '文件不能超过 ' . $size . ' KB']));
        // }
        Db::table('files')->insert(['file_name' => basename($savename), 'path' => '/storage/' . $savename, 'status' => 1, 'time' => time()]);
        exit(json_encode(['code' => 0, 'msg' => '上传成功', 'data' => ['src' => '/storage/' . $savename]]));
    }

    // 文件上传
    public function upload()
    {
        $path = Request::file('file');
        // 检查上传类型
        $setting = DB::table('setting')->where('names', 'base_setting')->find();
        $exts = 'gif|jpg|jpeg|png';
        $size = 2048;
        if ($setting && isset($setting['values'])) {
            $values = json_decode($setting['values'], true);
            $exts = $values['exts'] ?? 'gif|jpg|jpeg|png';
            $size = $values['size'] ?? 2048;
        }
        $exts = explode('|', $exts);
        $ext = $path->extension();
        if (!in_array($ext, $exts)) {
            // 静默删除临时文件
            @unlink($path->getRealPath());
            die(json_encode(['code' => 1, 'msg' => '不允许的上传类型' . $ext]));
        }
        // 检查文件大小
        $file_size = round(filesize($path->getRealPath()) / 1024 * 100) / 100;
        if ($file_size > (int)$size) {
            @unlink($path->getRealPath());
            die(json_encode(['code' => 1, 'msg' => '文件不能超过 ' . $size . ' KB']));
        }
        // 图片文件归类
        if (preg_match('/(gif|jpg|jpeg|png|bmp|webp|psd|svg|tiff)$/i', $ext)) {
            $path = Filesystem::disk('public')->putFile('images', $path);
        } else {
            $path = Filesystem::disk('public')->putFile('files', $path);
        }
        $url = '/storage/' . $path;
        // 附件信息保存文件管理
        DB::table('files')->insert(['file_name' => basename($path), 'path' => $url, 'status' => 1, 'time' => time()]);
        exit(json_encode(['code' => 0, 'msg' => '上传成功', 'data' => ['src' => $url, 'title' => basename($path)], 'files' => ['file' => $url]]));
    }

    // wangeditor编辑器上传
    public function wangeditor_upload()
    {
        $files = Request::file();
        $imags = [];
        $errors = [];
        // 检查上传类型
        $setting = DB::table('setting')->where('names', 'base_setting')->find();
        $exts = 'gif|jpg|jpeg|png';
        $size = 2048;
        if ($setting && isset($setting['values'])) {
            $values = json_decode($setting['values'], true);
            $exts = $values['exts'] ?? 'gif|jpg|jpeg|png';
            $size = $values['size'] ?? 2048;
        }
        $exts = explode('|', $exts);
        foreach ($files as $file) {
            $ext = $file->extension();
            if (!in_array($ext, $exts)) {
                @unlink($file->getRealPath());
                array_push($errors, '不允许的上传类型' . $ext);
            }
            $file_size = round(filesize($file->getRealPath()) / 1024 * 100) / 100;
            if ($file_size > (int)$size) {
                @unlink($file->getRealPath());
                array_push($errors, '文件不能超过 ' . $size . ' KB');
            }
            $path = Filesystem::disk('public')->putFile('uploads', $file);
            $url = '/storage/' . $path;
            DB::table('files')->insert(['file_name' => basename($path), 'path' => $url, 'status' => 1, 'time' => time()]);
            array_push($imags, $url);
        }
        if (!$errors) {
            $msg['errno'] = 0;
            $msg['data'] = $imags;
            return json($msg);
        } else {
            $msg['errno'] = 1;
            $msg['data'] = $imags;
            $msg['msg'] = "上传出错";
            return json($msg);
        }
    }

    // 计算孤立文件
    public function calc()
    {
        $paths = [];
        // 设置中是否引用文件
        $settings = DB::table('setting')->field('values')->select();
        foreach ($settings as $setting) {
            $values = json_decode($setting['values'], true);
            if ($values) {
                foreach ($values as $value) {
                    if (preg_match('/\/storage\/.+?\./i', implode(',', (array)$value))) {
                        $paths[] = $value;
                    }
                }
            } else {
                if (preg_match('/\/storage\/.+?\./i', implode(',', (array)$setting['values']))) {
                    $paths[] = $setting['values'];
                }
            }
        }
        // 账号管理是否引用文件
        $rows = Db::table('admin')->field('avatar')->select();
        foreach ($rows as $row) {
            if (preg_match('/\/storage\/.+?\./i', $row['avatar'])) {
                $paths[] = $row['avatar'];
            }
        }
        // 用户管理是否引用文件
        $rows = Db::table('users')->field('avatar')->select();
        foreach ($rows as $row) {
            if (preg_match('/\/storage\/.+?\./i', $row['avatar'])) {
                $paths[] = $row['avatar'];
            }
        }
        // 商品是否引用文件
        $rows = Db::table('product')->field('img')->select();
        foreach ($rows as $row) {
            if (preg_match('/\/storage\/.+?\./i', $row['img'])) {
                $paths[] = $row['img'];
            }
        }
        // 品牌是否引用文件
        $rows = Db::table('product_brands')->field('logo')->select();
        foreach ($rows as $row) {
            if (preg_match('/\/storage\/.+?\./i', $row['logo'])) {
                $paths[] = $row['logo'];
            }
        }
        // 商品sku是否引用文件
        $rows = Db::table('product_sku')->field('sku_content')->select();
        foreach($rows as $row) {
            if (preg_match_all('/<img[^>]*src=["\']([^"\']*\/storage\/.+?\.[^"\']*)["\'][^>]*>/i', $row['sku_content'], $matches)) {
                $paths = array_merge($paths, $matches[1]);
            }
        }
        // 文章是否引用文件
        $rows = Db::table('article')->field('img, content')->select();
        foreach ($rows as $row) {
            if (preg_match('/\/storage\/.+?\./i', $row['img'])) {
                $paths[] = $row['img'];
            }
            // 内容图片遍历
            if (preg_match_all('/<img[^>]*src=["\']([^"\']*\/storage\/.+?\.[^"\']*)["\'][^>]*>/i', $row['content'], $matches)) {
                $paths = array_merge($paths, $matches[1]);
            }
        }
        $paths = array_unique($paths);
        $files = DB::table('files')->field('id, file_name, path')->select();
        $ids0 = $ids1 = $ids2 = [];
        foreach ($files as $file) {
            $realpath = $this->app->getRootPath() . '/public/' . $file['path'];
            if (!is_file(str_replace('\\', DIRECTORY_SEPARATOR, $realpath))) {
                // 失效文件
                $ids2[] = $file['id'];
            } else {
                if (in_array($file['path'], $paths)) {
                    // 在用文件
                    $ids0[] = $file['id'];
                } else {
                    // 未使用文件
                    $ids1[] = $file['id'];
                }
            }
        }
        DB::table('files')->whereIn('id', $ids0)->update(['status' => 0]);
        DB::table('files')->whereIn('id', $ids1)->update(['status' => 1]);
        DB::table('files')->whereIn('id', $ids2)->update(['status' => 2]);
        exit(json_encode(['code' => 0, 'msg' => '共找到文件: ' . count($ids0) . ' 个在用，' . count($ids1) . ' 个未使用，' . count($ids2) . '个失效']));
    }

    // 文件重命名
    public function rename()
    {
        $id = (int)input('post.id');
        $row = Db::table('files')->where('id', $id)->find();
        !$row && exit(json_encode(['code' => 1, 'msg' => '数据不存在']));
        $row && $row['status'] == 0 && exit(json_encode(['code' => 1, 'msg' => '文件有在使用中，请重新计算状态']));
        $data['file_name'] = input('post.file_name');
        // 不能修改扩展名
        if ($ext = substr(strrchr($row['path'], '.'), 1)) {
            if ($ext !== substr(strrchr($data['file_name'], '.'), 1))
                exit(json_encode(['code' => 1, 'msg' => '不能修改扩展名 ' . $ext]));
        }
        // 验证名称为字母数字下划线
        $validate = $this->app->validate->rule(['name|文件名' => 'require|alphaDash']);
        !$validate->check(['name' => str_replace(strrchr($data['file_name'], '.'), '', $data['file_name'])]) && exit(json_encode(['code' => 1, 'msg' => $validate->getError()]));
        // 检查名称重复
        $check = Db::table('files')->where('file_name', $data['file_name'])->column('id');
        $check && !in_array($id, $check) && exit(json_encode(['code' => 1, 'msg' => '名称已存在']));
        // 执行重命名
        $oldpath = $this->app->getRootPath() . '/public/' . $row['path'];
        $data['path'] = str_replace($row['file_name'], $data['file_name'], $row['path']);
        $newpath = $this->app->getRootPath() . '/public/' . $data['path'];
        @rename($oldpath, $newpath);
        // 更新数据库
        Db::table('files')->where('id', $id)->update($data);
        exit(json_encode([
            'code' => 0, 'msg' => '重命名成功', 'data' => [
                'file_name' => $data['file_name'],
                'path' => $data['path'],
                'preview' => preg_match('/\/storage\/.+?\.(gif|jpg|jpeg|png|bmp|webp|psd|svg|tiff)$/i', $data['path']) ? (is_file($newpath) ? '<img src="' . $data['path'] . '" style="width:50%;height:100%" alt="preview" />' : '404 Err!') : ''
            ]
        ]));
    }

    // 删除文件
    public function del()
    {
        $id = input('post.id');
        $files = DB::table('files')->whereIn('id', $id)->select();
        $count = $files->count();
        $i = 0;
        $ids = [];
        foreach ($files as $file) {
            // 孤立和失效文件
            if ($file['status'] > 0) {
                $i++;
                $ids[] = $file['id'];
                $realpath = $this->app->getRootPath() . '/public/' . $file['path'];
                // 删除硬盘文件
                is_file($realpath) && @unlink($realpath);
            }
        }
        // 删除数据库存储信息
        Db::table('files')->whereIn('id', $ids)->delete();
        if ($i == $count) exit(json_encode(['code' => 0, 'msg' => '删除成功']));
        elseif ($i == 0) exit(json_encode(['code' => 1, 'msg' => '文件有在使用，删除失败！']));
        else exit(json_encode(['code' => 0, 'msg' => '共删除' . $i . '个文件，' . ($count - $i) . '个文件在使用']));
    }
}
